<?php

namespace App\Logics;


use App\Models\User;
use App\Service\Ali\AliCaptcha;
use App\Service\Base\Logic;
use App\Service\Curl;
use App\Service\WeChat\MiniWx;
use App\Service\WeChat\OpenWx;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;

class AccountLogic extends Logic
{

    // 登录注册操作

    /**
     * 这里是按他们的一个奇葩要求做的不完善的用户注册登录操作
     *   1、使用openid写入用户表
     *   2、在用手机号更新数据表中的手机号信息
     * 这样做，以后则
     *   1、不能在其他地方添加用户，不然会出问题
     *   2、不能删除只有openID的垃圾数据，可能会使用户登录报错
     *
     */

    // 获取 token
    public function token()
    {
        $uid    = $this->option()->getData('uid', 0, 'intval');
        $mobile = $this->option()->getData('mobile', '', 'trim');
        if(empty($uid) && empty($mobile)){
            return $this->_returnFail('获取指定用户的token！');
        }

        $where = [];
        if($uid){
            $where = ['id' => $uid];
        }
        if($mobile){
            $where = ['mobile' => $mobile];
        }

        $userDb = new User();
        $info   = $userDb->where($where)->first();
        if(empty($info)){
            return $this->_returnFail('用户不存在！');
        }
        if($info->status === 0){
            return $this->_returnFail('用户被禁用！');
        }

        $info   = $info->toArray();
        $token  = Crypt::encryptString(json_encode($info, JSON_UNESCAPED_UNICODE));
        $result = ['token' => $token, 'user' => $info,];

        return $result;
    }


    // 小程序登录（没有，则注册）（小程序端使用：wx_code）
    public function miniLoginWxCode()
    {
        $option = $this->option();
        $wxCode = $option->getData('wx_code', null, 'trim');  // 微信code用于获取openID
        if(empty($wxCode)){
            return $this->_returnFail('请先获取微信code！！');
        }


        // 获取微信openID
        /**
         *  var userInfo = res.userInfo
         * var nickName = userInfo.nickName
         * var avatarUrl = userInfo.avatarUrl
         * var gender = userInfo.gender //性别 0：未知、1：男、2：女
         * var province = userInfo.province
         * var city = userInfo.city
         * var country = userInfo.country
         */
        //$wx   = new OpenWx();
        //$res  = $wx->getUserByMini($wxCode);

        $mini = new MiniWx();
        $data = $mini->getOpenidByMini($wxCode);
        if(empty($data)){
            return $this->_returnFail('获取微信信息失败！！');
        }
        if(!empty($data['errcode'])){
            return $this->_returnFail($data['errmsg']);
        }

        Log::info('Request | 微信小程序请求openID返回 |', $data);
        $openid = $data['openid'];

        // 判断微信是否存在
        $userDb = new User();
        $where  = [['openid', '=', $openid], ['status', '>=', 0]];
        $info   = $userDb->isCache(true)->oneFind($where);
        if(empty($info)){
            // 如果没有 则注册
            $salt  = Str::random(4);
            $_pass = $userDb->add_md5(123456, $salt);  // 密码
            $data  = ['openid' => $openid, 'salt' => $salt, 'password' => $_pass,];
            $uid   = $userDb->oneAdd($data);
            // 重新查询
            $info = $userDb->isCache(true)->oneFind($where);
        }
        if($info['status'] === 0){
            return $this->_returnFail('对不起，您已经被禁用！！');
        }

        // 是否有有时候
        $is_mobile = empty($info['mobile']) ? false : true;

        // 清理缓存
        $userDb->deleteCacheShow($info);

        // 返回
        //$user = ['id' => $userId, 'nickname' => $info['email'], 'mobile' => $info['mobile']];
        $token  = Crypt::encryptString(json_encode($info, JSON_UNESCAPED_UNICODE));
        $result = ['token' => $token, 'is_mobile' => $is_mobile,];

        return $result;
    }


    // 小程序获取手机号 更新手机号
    public function getMiniPhoneUpdate()
    {
        $option  = $this->option();
        $iv      = $option->getData('iv', null, 'trim');
        $key     = $option->getData('session_key', null, 'trim');
        $encrypt = $option->getData('encrypted', null, 'trim');
        if(empty($encrypt) || empty($key) || empty($iv)){
            return $this->_returnFail('请传递解析参数！！');
        }

        // 解析获取手机号
        $res    = $this->miniDecrypt($encrypt, $iv, $key);
        $res    = json_decode($res, true);
        $mobile = $res['mobile'] ?? '';
        if(empty($mobile)){
            return $this->_returnFail('获取用户手机号失败！');
        }


        // 用户信息
        $user = $option->token('user', 'user-token');
        $option->throwIf($user === false, $option->getError(), LOGIN_ERROR);
        if(empty($user)){
            return $this->_returnFail('请传递用户token！');
        }


        // 更新头像  和 名称
        $userId = $user['id'];
        $updata = ['last_ip' => $option->getIp(), 'last_time' => LARAVEL_TIME,];
        if((!empty($head_img)) && empty($user['head_img'])){
            $updata['head_img'] = $head_img;
        }
        if((!empty($nickname)) && empty($user['nickname'])){
            $updata['nickname'] = $nickname;
        }
        if((!empty($mobile)) && empty($user['mobile'])){
            $username = $user['salt'].substr($user['id'] + $mobile, -4);
            // 更新
            $updata['mobile']   = $mobile;
            $updata['username'] = $username;
            $updata['nickname'] = $username;
        }

        $userDb = new User();
        $rst    = $userDb->where('id', $userId)->update($updata);
        if($rst === false){
            return $this->_returnFail($userDb->getError());
        }

        // 清理缓存
        $userDb->deleteCacheShow($user, $updata);

        // 返回
        $token  = Crypt::encryptString(json_encode($user, JSON_UNESCAPED_UNICODE));
        $result = ['token' => $token, 'user' => $user,];

        return $result;
    }


    ##########################################################################################################
    // 获取 openID:o4H167e6PNOYgpwJKihvj1ZdqIk4
    public function getMiniOpenid()
    {
        $option = $this->option();
        $wxCode = $option->getData('wx_code', null, 'trim');  // 微信code用于获取openID
        if(empty($wxCode)){
            return $this->_returnFail('请先获取微信code！！');
        }

        $mini = new MiniWx();
        $res  = $mini->getOpenidByMini($wxCode);

        //$res = $mini->_getOpenid($token, $code);

        return $res;
    }

    // 获取
    public function getMiniPhone()
    {
        $option = $this->option();
        $code   = $option->getData('code', null, 'trim');
        $openid = $option->getData('openid', null, 'trim');
        if(empty($openid)){
            return $this->_returnFail('请先获取微信openID！！');
        }
        if(empty($code)){
            return $this->_returnFail('请先获取微信code！！');
        }

        $mini   = new MiniWx();
        $_token = $mini->getAccessToken();
        $res    = $mini->getPhoneByMini($_token, $openid, $code);

        //$res = $mini->_getOpenid($token, $code);

        return $res;
    }

    //  解析小程序信息
    public function miniDecode()
    {
        $code    = '56bf7db84a7a9ec86728ba7dfe05ab5d863a73104cce00d104d4e16b0398e26c';
        $encrypt = 'hAnN9iW74tRsnnlfabGN+je8oulDTsNymmWT8+Z8thdckwDVa5m2WgN9uh/W+tz6VXcwKPB8FfmWc1AulqTHsRwkz6tQpj/kLivcugiZQDTQc3f1EuBGOtiNN8JRODwnmx2xn8cx8276admAVjsnr5vcwTic9c9Mn00b++IlqTeOYWcgAxGljupymKSWCu4Mr05t3ARlzw2Cl/sgAFwytQ==';
        $iv      = 'DlIae/I1SogwLN51DEz6Xw==';
        $key     = 'NNoYdVDI8qXT+shOMF6krQ==';

        $option  = $this->option();
        $iv      = $option->getData('iv', null, 'trim');
        $key     = $option->getData('session_key', null, 'trim');
        $encrypt = $option->getData('encrypted', null, 'trim');
        if(empty($encrypt) || empty($key) || empty($iv)){
            return $this->_returnFail('请传递解析参数！！');
        }

        $res = $this->miniDecrypt($encrypt, $iv, $key);
        $res = json_decode($res, true);

        return $res;
    }

    ##########################################################################################################
    ## 阿里云弹出式验证码 验证
    public function onAliCaptcha()
    {
        $opt     = $this->option();
        $param   = $opt->getData('captchaVerifyParam', null, 'trim');
        $sceneId = 'qonabfwj';  // 场景ID。根据步骤二新建验证场景后，您可以在验证码场景列表，获取该场景的场景ID

        /*$curl = new Curl();
        $post = ['CaptchaVerifyParam' => $param, 'SceneId' => $sceneId];
        $url  = 'https://captcha.cn-shanghai.aliyuncs.com/VerifyIntelligentCaptcha';
        $res  = $curl->post($post)->request($url);
        $res  = (array)simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA);*/

        // var_dump($res);
        //$AliCaptcha = new AliCaptcha();
        $res = AliCaptcha::main($param);


        return $res;
    }

    ##########################################################################################################
    // 假设你有一个WechatService类来处理微信相关的逻辑
    public function getSessionKeyAndOpenid($code)
    {
        $url      = "https://api.weixin.qq.com/sns/jscode2session";
        $params   = [
            'appid'      => config('wechat.mini_program.app_id'),
            'secret'     => config('wechat.mini_program.secret'),
            'js_code'    => $code,
            'grant_type' => 'authorization_code',
        ];
        $response = json_decode(file_get_contents($url.'?'.http_build_query($params)), true);
        if(isset($response['errcode'])){
            throw new Exception($response['errmsg']);
        }

        return $response;
    }

    // 获取小程序各种数据的 加密（所有数据来源于小程序传递过来的）
    public function miniEncrypt($data, $iv, $key)
    {
        $block_size = 16;
        //补位处理
        $padding = $block_size - strlen($data) % $block_size;
        $data    .= str_repeat(chr($padding), $padding);
        //加密
        $encrypted = openssl_encrypt($data, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);

        return base64_encode($encrypted);
    }

    // 获取小程序各种数据的 解密（所有数据来源于小程序传递过来的）
    public function miniDecrypt($encrypted, $iv, $key)
    {
        $aesKey    = base64_decode($key);
        $aesIV     = base64_decode($iv);
        $encrypted = base64_decode($encrypted);
        $decrypted = openssl_decrypt($encrypted, 'AES-128-CBC', $aesKey, OPENSSL_RAW_DATA, $aesIV);

        $block_size = 16;
        //去除补位信息
        $padding = ord(substr($decrypted, -1));
        if($padding < 1 || $padding > $block_size){
            $padding = 0;
        }
        $decrypted = substr($decrypted, 0, strlen($decrypted) - $padding);

        return $decrypted;
    }

}


